package xyz.xiaoshengfu.xrpc.admin.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import xyz.xiaoshengfu.xrpc.admin.service.XRpcAdminService;
import xyz.xiaoshengfu.xrpc.common.JedisClientPool;
import xyz.xiaoshengfu.xrpc.config.ApplicationConfig;
import xyz.xiaoshengfu.xrpc.config.ProviderServiceInfor;
import xyz.xiaoshengfu.xrpc.config.ServiceBean;
import xyz.xiaoshengfu.xrpc.config.XRpcConfig;

@Service()
public class XRpcAdminServiceImpl implements XRpcAdminService {

	@Value("${login.account}")
	private String loginAccount;
	@Value("${login.password}")
	private String loginPassword;

	@Autowired
	private JedisClientPool jedisClientPool;

	public final ReentrantLock lock = new ReentrantLock();

	private static final ObjectMapper objectMapper = new ObjectMapper();

	private static final JavaType mapStringListProviderServiceInforType;

	private List<XRpcConfig> xRpcConfigList = new ArrayList<XRpcConfig>();

	private Map<String, Map<String, List<ProviderServiceInfor>>> applicationReferenceServiceListMapMap = new HashMap<String, Map<String, List<ProviderServiceInfor>>>();

	static {
		mapStringListProviderServiceInforType = objectMapper.getTypeFactory().constructMapType(HashMap.class,
				objectMapper.getTypeFactory().constructType(String.class),
				objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, ProviderServiceInfor.class));
	}

	public XRpcAdminServiceImpl() {
		super();
	}

	public XRpcAdminServiceImpl(JedisClientPool jedisClientPool) {
		super();
		this.jedisClientPool = jedisClientPool;
	}

	@Override
	public boolean adminLogin(String account, String password) {
		if (StringUtils.isNoneBlank(loginAccount) && StringUtils.isNotBlank(loginAccount)) {
			if (loginAccount.equals(account) && loginPassword.equals(password)) {
				return true;
			} else {
				return false;
			}
		}
		return true;
	}

	@Override
	public Map<String, Integer> getXRpcConfigListInfor() {
		Map<String, Integer> infor = new HashMap<String, Integer>(3);
		infor.put("totalApplication", xRpcConfigList.size());
		int totalProvider = 0;
		int totalConsumer = 0;
		for (XRpcConfig xRpcConfig : xRpcConfigList) {
			if (xRpcConfig.getServiceBeanList() != null && xRpcConfig.getServiceBeanList().size() > 0) {
				totalProvider++;
			}
			if (xRpcConfig.getReferenceBeanList() != null && xRpcConfig.getReferenceBeanList().size() > 0) {
				totalConsumer++;
			}
		}
		infor.put("totalProvider", totalProvider);
		infor.put("totalConsumer", totalConsumer);
		return infor;
	}

	@Override
	public List<XRpcConfig> getXRpcConfigList() {
		lock.lock();
		try {
			return xRpcConfigList;
		} finally {
			lock.unlock();
		}
	}

	@Override
	public List<XRpcConfig> getXRpcConfigListByApplicationName(String applicationName) {
		lock.lock();
		try {
			List<XRpcConfig> anXRpcConfigList = new ArrayList<XRpcConfig>();
			if (StringUtils.isNotBlank(applicationName)) {
				String lapplicationName = applicationName.toLowerCase();
				for (XRpcConfig xRpcConfig : xRpcConfigList) {
					ApplicationConfig applicationConfig = xRpcConfig.getApplicationConfig();
					if (applicationConfig != null && StringUtils.isNotBlank(applicationConfig.getName())
							&& applicationConfig.getName().toLowerCase().contains(lapplicationName)) {
						anXRpcConfigList.add(xRpcConfig);
					}
				}
			}
			return anXRpcConfigList;
		} finally {
			lock.unlock();
		}
	}

	@Override
	public XRpcConfig getXRpcConfigByApplicationName(String applicationName) {
		lock.lock();
		try {
			for (XRpcConfig xRpcConfig : xRpcConfigList) {
				ApplicationConfig applicationConfig = xRpcConfig.getApplicationConfig();
				if (applicationConfig != null && applicationName.equals(applicationConfig.getName())) {
					return xRpcConfig;
				}
			}
			return null;
		} finally {
			lock.unlock();
		}
	}

	@Override
	public Map<String, List<ProviderServiceInfor>> getApplicationReferenceServiceListMap(String applicationName) {
		lock.lock();
		try {
			return applicationReferenceServiceListMapMap.get(applicationName);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public Map<String, List<String>> getApplicationServiceReferenceListMap(String applicationName) {
		lock.lock();
		try {
			XRpcConfig xRpcConfig = getXRpcConfigByApplicationName(applicationName);
			if (xRpcConfig != null) {
				List<ServiceBean> serviceBeanList = xRpcConfig.getServiceBeanList();
				if (serviceBeanList != null) {
					Map<String, List<String>> map = new HashMap<String, List<String>>(serviceBeanList.size());
					for (ServiceBean serviceBean : serviceBeanList) {
						List<String> applicationNameList = new ArrayList<String>();
						for (Entry<String, Map<String, List<ProviderServiceInfor>>> entry : applicationReferenceServiceListMapMap
								.entrySet()) {
							List<ProviderServiceInfor> providerServiceInforList = entry.getValue()
									.get(serviceBean.getServiceInterface());
							if (providerServiceInforList != null) {
								for (ProviderServiceInfor providerServiceInfor : providerServiceInforList) {
									if (applicationName.equals(providerServiceInfor.getApplicationName())) {
										applicationNameList.add(entry.getKey());
										break;
									}
								}
							}
						}
						map.put(serviceBean.getServiceInterface(), applicationNameList);
					}
					return map;
				}
			}
			return null;
		} finally {
			lock.unlock();
		}
	}

	private void adminRefreshData() {
		lock.lock();
		try {
			List<XRpcConfig> nxRpcConfigList = new ArrayList<XRpcConfig>();
			Map<String, Map<String, List<ProviderServiceInfor>>> napplicationReferenceServiceListMapMap = new HashMap<String, Map<String, List<ProviderServiceInfor>>>();
			Set<String> xRpcConfigKeys = jedisClientPool.keys("xRpcConfig:*");
			if (xRpcConfigKeys != null) {
				for (String key : xRpcConfigKeys) {
					String jsonXRpcConfig = jedisClientPool.get(key);
					if (StringUtils.isNoneBlank(jsonXRpcConfig)) {
						XRpcConfig xRpcConfig = null;
						try {
							xRpcConfig = objectMapper.readValue(jsonXRpcConfig, XRpcConfig.class);
						} catch (Exception e) {
							e.printStackTrace();
						}
						if (xRpcConfig != null) {
							nxRpcConfigList.add(xRpcConfig);
						}
					}
				}
			}
			xRpcConfigList = nxRpcConfigList;
			Set<String> xRpcConsumerKeys = jedisClientPool.keys("xRpcConsumer:*");
			if (xRpcConsumerKeys != null) {
				for (String key : xRpcConsumerKeys) {
					String jsonXRpcConsumerReferenceList = jedisClientPool.get(key);
					if (StringUtils.isNoneBlank(jsonXRpcConsumerReferenceList)) {
						Map<String, List<ProviderServiceInfor>> map = null;
						try {
							map = objectMapper.readValue(jsonXRpcConsumerReferenceList,
									mapStringListProviderServiceInforType);
						} catch (Exception e) {
							e.printStackTrace();
						}
						if (map != null) {
							String[] strings = key.split(":");
							if (strings.length == 2) {
								napplicationReferenceServiceListMapMap.put(strings[1], map);
							}
						}
					}
				}
			}
			applicationReferenceServiceListMapMap = napplicationReferenceServiceListMapMap;
		} finally {
			lock.unlock();
		}
	}

	@PostConstruct
	private void adminScheduledRefreshData() {
		Executors.newScheduledThreadPool(1).scheduleWithFixedDelay(() -> {
			adminRefreshData();
		}, 0L, 60L, TimeUnit.SECONDS);

	}

}
